#include "PlanetAddTask.hh"
#include "XmlServerThread.hh"
#include "../World/Planet/BuildBattleship.hh"
#include "../World/Planet/BuildColonyship.hh"
#include "../World/Planet/BuildDwelling.hh"
#include "../World/Planet/BuildFactory.hh"
#include "../World/Planet/BuildFarm.hh"
#include "../World/Planet/BuildFighter.hh"
#include "../World/Planet/BuildProducts.hh"
#include "../World/Planet/BuildReactor.hh"
#include "../World/Planet/BuildTank.hh"
#include "../World/Planet/BuildTransportship.hh"
#include "../Exception.hh"

using namespace Network;
using namespace World;

struct StarIdInvalid {
    void operator () () {
        throw NonFatalProtocolError("game.planet_add_task.star_id invalid");
    }
};

struct PlanetIdInvalid {
    void operator () () {
        throw NonFatalProtocolError("game.planet_add_task.planet_id invalid");
    }
};

struct TaskInvalid {
    void operator () () {
        throw NonFatalProtocolError("game.planet_add_task.task invalid");
    }
};

struct AmountInvalid {
    void operator () () {
        throw NonFatalProtocolError("game.planet_add_task.amount invalid");
    }
};

spPlanetAddTask PlanetAddTask::construct(QDomElement const& message) {
    QDomElement const starIdElem = message.firstChildElement("star_id");
    QDomElement const planetIdElem = message.firstChildElement("planet_id");
    QDomElement const taskElem = message.firstChildElement("task");
    QDomElement const amountElem = message.firstChildElement("amount");
    u8 const starId = ::parse_num< u8, StarIdInvalid >(starIdElem);
    u8 const planetId = ::parse_num< u8, PlanetIdInvalid >(planetIdElem);
    QString const task = ::parse_str< TaskInvalid >(taskElem);
    u8 const amount = ::parse_num< u8, AmountInvalid >(amountElem);
    return spPlanetAddTask(new PlanetAddTask(starId, planetId, task, amount));
}

PlanetAddTask::PlanetAddTask(
  u8 starId, u8 planetId, QString const& task, u8 amount
):
    starId(starId),
    planetId(planetId),
    task(task),
    amount(amount) {}

QDomDocument PlanetAddTask::to_xml() const {
    QDomDocument doc;
    QDomElement gameElem = doc.createElement("game");
    QDomElement planetAddTaskElem = doc.createElement("planet_add_task");
    doc.appendChild(gameElem);
    gameElem.appendChild(planetAddTaskElem);
    ::to_xml(planetAddTaskElem, "star_id",   starId);
    ::to_xml(planetAddTaskElem, "planet_id", planetId);
    ::to_xml(planetAddTaskElem, "task",      task);
    ::to_xml(planetAddTaskElem, "amount",    amount);
    return doc;
}

void PlanetAddTask::process_on_server(XmlServerThread& thread) {
    if (thread.get_state() != GAME)
        throw NonFatalProtocolError("game.planet_add_task unexpected");

    spGalaxy galaxy = thread.get_player()->get_galaxy();
    spStar star = galaxy->get_star(starId);
    spPlanet planet = star->get_planet(planetId);

    if (task == "battleship")
        planet->add_task(new Planet::BuildBattleship(amount));
    else if (task  == "colonyship")
        planet->add_task(new Planet::BuildColonyship(amount));
    else if (task  == "dwelling")
        planet->add_task(new Planet::BuildDwelling(amount));
    else if (task  == "factory")
        planet->add_task(new Planet::BuildFactory(amount));
    else if (task  == "farm")
        planet->add_task(new Planet::BuildFarm(amount));
    else if (task  == "fighter")
        planet->add_task(new Planet::BuildFighter(amount));
    else if (task  == "products")
        planet->add_task(new Planet::BuildProducts(amount));
    else if (task  == "reactor")
        planet->add_task(new Planet::BuildReactor(amount));
    else if (task  == "tank")
        planet->add_task(new Planet::BuildTank(amount));
    else if (task  == "transportship")
        planet->add_task(new Planet::BuildTransportship(amount));
    else
        throw NonFatalProtocolError("invalid task name");
}
